package com.lyncs.ods.task;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.lyncs.ods.constant.LanguageEnum;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.modules.goods.model.SpuDetail;
import com.lyncs.ods.modules.goods.model.SpuInfo;
import com.lyncs.ods.modules.goods.service.SpuDetailService;
import com.lyncs.ods.modules.goods.service.SpuInfoService;
import com.lyncs.ods.modules.setting.model.CountryInfo;
import com.lyncs.ods.modules.setting.model.IndustryInfo;
import com.lyncs.ods.modules.setting.service.CountryInfoService;
import com.lyncs.ods.modules.setting.service.IndustryInfoService;
import com.lyncs.ods.utils.MD5;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.util.URLEncoder;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import com.lyncs.ods.utils.HttpGet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author alex
 * @date 2022/6/10 21:57
 * @description
 */
@Component
@Slf4j
public class TranslateTask {

    public static final Integer PAGE_SIZE = 100;
    private static final Map<String, String> LANGUAGE_BAI_DU_MAP = Map.of(
            LanguageEnum.ZH_HK.getLanguage(), "cht",
            LanguageEnum.EN_US.getLanguage(), "en"
    );
    public static final String TRANSLATE_URL = "http://api.fanyi.baidu.com/api/trans/vip/translate";

    @Value("${baidu.translate.appId}")
    private String appId;
    @Value("${baidu.translate.appSecret}")
    private String appSecret;
    @Autowired
    private SpuInfoService spuInfoService;
    @Autowired
    private SpuDetailService spuDetailService;
    @Autowired
    private CountryInfoService countryInfoService;
    @Autowired
    private IndustryInfoService industryInfoService;

    public void spu() {
        Long starId = 0L;
        int onceSize;
        do {
            List<SpuInfo> spuInfos = spuInfoService.lambdaQuery().ge(SpuInfo::getId, starId).orderByAsc(SpuInfo::getId).last(" limit " + PAGE_SIZE).list();
            List<Long> spuIds = spuInfos.stream().map(SpuInfo::getId).collect(Collectors.toList());
            List<SpuDetail> spuDetails = spuDetailService.lambdaQuery().in(SpuDetail::getSpuId, spuIds).list();
            Map<Long, List<SpuDetail>> spuDetailMap = spuDetails.stream().collect(Collectors.groupingBy(SpuDetail::getSpuId));
            Map<String, Map<String, String>> transResultMap = new HashMap<>();
            spuInfos.forEach(spu -> {
                Map<String, Map<String, String>> oneSpuResult = doOnce(spu, spuDetailMap.get(spu.getId()));
                transResultMap.putAll(oneSpuResult);
            });
            spuInfos.forEach(spu -> {
                Map<String, String> spuLanguageMap = transResultMap.get(spu.getName().trim());
                spu.setName(spu.getName().trim()).setLanguageJson(JSONObject.toJSONString(spuLanguageMap, SerializerFeature.WriteMapNullValue));
            });
            spuDetails.forEach(spuDetail -> {
                Map<String, String> spuLanguageMap = transResultMap.get(spuDetail.getName());
                spuDetail.setName(spuDetail.getName().trim()).setLanguageJson(JSONObject.toJSONString(spuLanguageMap, SerializerFeature.WriteMapNullValue));
            });
            spuInfoService.updateBatchById(spuInfos);
            spuDetailService.updateBatchById(spuDetails);
            starId = spuInfos.stream().mapToLong(SpuInfo::getId).max().orElse(0L);
            onceSize = spuInfos.size();
        } while (onceSize >= PAGE_SIZE);
    }

    public void country() {
        Long starId = 0L;
        int onceSize;
        do {
            List<CountryInfo> countryInfos = countryInfoService.lambdaQuery().ge(CountryInfo::getId, starId).orderByAsc(CountryInfo::getId).last(" limit " + PAGE_SIZE).list();
            List<String> words = countryInfos.stream().map(CountryInfo::getName).map(String::trim).collect(Collectors.toList());
            Map<String, Map<String, String>> standardWordMap = words.stream().map(word -> {
                Map<String, String> languageMap = new HashMap<>(3);
                languageMap.put(LanguageEnum.ZH_CN.getLanguage(), word);
                Map<String, Map<String, String>> wordLanguageMap = new HashMap<>();
                wordLanguageMap.put(word, languageMap);
                return wordLanguageMap;
            }).collect(HashMap::new, HashMap::putAll, HashMap::putAll);
            LANGUAGE_BAI_DU_MAP.forEach((k, v) -> {
                String salt = String.valueOf(System.currentTimeMillis());
                String word = StringUtils.joinWith(LyncsOdsConstant.Common.NEW_LINE, words.toArray());
                Map<String, String> paramMap = new HashMap<>();
                paramMap.put("from", "zh");
                paramMap.put("to", v);
                paramMap.put("appid", appId);
                paramMap.put("salt", salt);
                paramMap.put("sign", getSign(word, salt));
                paramMap.put("q", word);
                String resp = HttpGet.get(TRANSLATE_URL, paramMap);
                if (StringUtils.isEmpty(resp) || !JSONValidator.from(resp).validate()) {
                    log.error("translate failed, from {} to {}, req:{}, resp:{}", "zh", v, JSONObject.toJSONString(paramMap), resp);
                    return;
                }
                JSONObject respJson = JSONObject.parseObject(resp);
                if (!respJson.containsKey("trans_result")) {
                    log.error("translate failed, from {} to {}, req:{}, respJson:{}", "zh", v, JSONObject.toJSONString(paramMap), respJson);
                    return;
                }
                JSONArray transResultArr = respJson.getJSONArray("trans_result");
                for (int i = 0; i < transResultArr.size(); i++) {
                    JSONObject itemJson = transResultArr.getJSONObject(i);
                    String src = itemJson.getString("src");
                    String dst = itemJson.getString("dst");
                    Map<String, String> thisWordLanguageMap = standardWordMap.get(URLDecoder.decode(src, StandardCharsets.UTF_8));
                    if (MapUtils.isEmpty(thisWordLanguageMap)) {
                        log.error("update failed,{}", URLDecoder.decode(src, StandardCharsets.UTF_8));
                        continue;
                    }
                    thisWordLanguageMap.put(k, dst);
                }
            });
            countryInfos.forEach(country -> {
                Map<String, String> spuLanguageMap = standardWordMap.get(country.getName().trim());
                country.setName(country.getName().trim()).setLanguageJson(JSONObject.toJSONString(spuLanguageMap, SerializerFeature.WriteMapNullValue));
            });
            countryInfoService.updateBatchById(countryInfos);
            starId = countryInfos.stream().mapToLong(CountryInfo::getId).max().orElse(0L);
            onceSize = countryInfos.size();
        } while (onceSize >= PAGE_SIZE);
    }

    public void industry() {
        Long starId = 0L;
        int onceSize;
        do {
            List<IndustryInfo> industryInfos = industryInfoService.lambdaQuery().ge(IndustryInfo::getId, starId).orderByAsc(IndustryInfo::getId).last(" limit " + PAGE_SIZE).list();
            List<String> words = industryInfos.stream().map(IndustryInfo::getName).map(String::trim).collect(Collectors.toList());
            Map<String, Map<String, String>> standardWordMap = words.stream().map(word -> {
                Map<String, String> languageMap = new HashMap<>(3);
                languageMap.put(LanguageEnum.ZH_CN.getLanguage(), word);
                Map<String, Map<String, String>> wordLanguageMap = new HashMap<>();
                wordLanguageMap.put(word, languageMap);
                return wordLanguageMap;
            }).collect(HashMap::new, HashMap::putAll, HashMap::putAll);
            LANGUAGE_BAI_DU_MAP.forEach((k, v) -> {
                String salt = String.valueOf(System.currentTimeMillis());
                String word = StringUtils.joinWith(LyncsOdsConstant.Common.NEW_LINE, words.toArray());
                Map<String, String> paramMap = new HashMap<>();
                paramMap.put("from", "zh");
                paramMap.put("to", v);
                paramMap.put("appid", appId);
                paramMap.put("salt", salt);
                paramMap.put("sign", getSign(word, salt));
                paramMap.put("q", word);
                String resp = HttpGet.get(TRANSLATE_URL, paramMap);
                if (StringUtils.isEmpty(resp) || !JSONValidator.from(resp).validate()) {
                    log.error("translate failed, from {} to {}, req:{}, resp:{}", "zh", v, JSONObject.toJSONString(paramMap), resp);
                    return;
                }
                JSONObject respJson = JSONObject.parseObject(resp);
                if (!respJson.containsKey("trans_result")) {
                    log.error("translate failed, from {} to {}, req:{}, respJson:{}", "zh", v, JSONObject.toJSONString(paramMap), respJson);
                    return;
                }
                JSONArray transResultArr = respJson.getJSONArray("trans_result");
                for (int i = 0; i < transResultArr.size(); i++) {
                    JSONObject itemJson = transResultArr.getJSONObject(i);
                    String src = itemJson.getString("src");
                    String dst = itemJson.getString("dst");
                    Map<String, String> thisWordLanguageMap = standardWordMap.get(URLDecoder.decode(src, StandardCharsets.UTF_8));
                    if (MapUtils.isEmpty(thisWordLanguageMap)) {
                        log.error("update failed,{}", URLDecoder.decode(src, StandardCharsets.UTF_8));
                        continue;
                    }
                    thisWordLanguageMap.put(k, dst);
                }
            });
            industryInfos.forEach(industry -> {
                Map<String, String> spuLanguageMap = standardWordMap.get(industry.getName().trim());
                industry.setName(industry.getName().trim()).setLanguageJson(JSONObject.toJSONString(spuLanguageMap, SerializerFeature.WriteMapNullValue));
            });
            industryInfoService.updateBatchById(industryInfos);
            starId = industryInfos.stream().mapToLong(IndustryInfo::getId).max().orElse(0L);
            onceSize = industryInfos.size();
        } while (onceSize >= PAGE_SIZE);
    }

    private String getSign(String word, String salt) {
        String str = StringUtils.join(appId, word, salt, appSecret);
        return MD5.md5(str);
    }

    private Map<String, Map<String, String>> doOnce(SpuInfo spuInfo, List<SpuDetail> spuDetails) {
        List<String> words = new ArrayList<>();
        words.add(spuInfo.getName());
        if (CollectionUtils.isNotEmpty(spuDetails)) {
            words.addAll(spuDetails.stream().map(SpuDetail::getName).filter(Objects::nonNull).collect(Collectors.toList()));
        }
        List<String> finalWords = words.stream().map(String::trim).collect(Collectors.toList());
        Map<String, Map<String, String>> standardWordMap = words.stream().map(word -> {
            Map<String, String> languageMap = new HashMap<>(3);
            languageMap.put(LanguageEnum.ZH_CN.getLanguage(), word);
            Map<String, Map<String, String>> wordLanguageMap = new HashMap<>();
            wordLanguageMap.put(word, languageMap);
            return wordLanguageMap;
        }).collect(HashMap::new, HashMap::putAll, HashMap::putAll);
        LANGUAGE_BAI_DU_MAP.forEach((k, v) -> {
            String salt = String.valueOf(System.currentTimeMillis());
            String word = StringUtils.joinWith(LyncsOdsConstant.Common.NEW_LINE, finalWords.toArray());
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("from", "zh");
            paramMap.put("to", v);
            paramMap.put("appid", appId);
            paramMap.put("salt", salt);
            paramMap.put("sign", getSign(word, salt));
            paramMap.put("q", word);
            String resp = HttpGet.get(TRANSLATE_URL, paramMap);
            if (StringUtils.isEmpty(resp) || !JSONValidator.from(resp).validate()) {
                log.error("translate failed, from {} to {}, spuId:{}, req:{}, resp:{}", "zh", v, spuInfo.getId(), JSONObject.toJSONString(paramMap), resp);
                return;
            }
            JSONObject respJson = JSONObject.parseObject(resp);
            if (!respJson.containsKey("trans_result")) {
                log.error("translate failed, from {} to {}, spuId:{}, req:{}, respJson:{}", "zh", v, spuInfo.getId(), JSONObject.toJSONString(paramMap), respJson);
                return;
            }
            JSONArray transResultArr = respJson.getJSONArray("trans_result");
            for (int i = 0; i < transResultArr.size(); i++) {
                JSONObject itemJson = transResultArr.getJSONObject(i);
                String src = itemJson.getString("src");
                String dst = itemJson.getString("dst");
                Map<String, String> thisWordLanguageMap = standardWordMap.get(URLDecoder.decode(src, StandardCharsets.UTF_8));
                if (MapUtils.isEmpty(thisWordLanguageMap)) {
                    log.error("update failed,{}", URLDecoder.decode(src, StandardCharsets.UTF_8));
                    continue;
                }
                thisWordLanguageMap.put(k, dst);
            }
        });
        return standardWordMap;
    }
}
